package cn.dansj.configure;

import cn.dansj.common.utils.json.DictMap;
import cn.dansj.common.utils.crypt.EncryptionAndDecryptionException;
import cn.dansj.common.utils.crypt.RsaUtils;
import cn.dansj.common.request.resolver.EAD;
import cn.dansj.common.redis.RedisUtils;
import cn.dansj.common.utils.transfer.Verification;
import org.springframework.context.annotation.Configuration;

import javax.crypto.IllegalBlockSizeException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

@Configuration
public class EncryptAndDecrypt implements EAD {
    private final RedisUtils redisUtils;

    public EncryptAndDecrypt(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    public RsaUtils.RSAKeyPair getKeyPem() throws NoSuchAlgorithmException {
        final Map<Object, Object> rsaKey = redisUtils.hgetall("rsaKey");
        if (Verification.checkNull(rsaKey) || Verification.checkAnyNull(rsaKey.get("privateKey"), rsaKey.get("publicKey"))) {
            final RsaUtils.RSAKeyPair rsaKeyPair = RsaUtils.generateKeyPair();
            redisUtils.hmset("rsaKey", DictMap.from(rsaKeyPair));
            return rsaKeyPair;
        } else {
            return new RsaUtils.RSAKeyPair(rsaKey.get("publicKey").toString(), rsaKey.get("privateKey").toString());
        }
    }

    @Override
    public String decrypt(String data) {
        try {
            if (Verification.checkNull(data)) return "";
            return RsaUtils.decryptByPrivateKey(getKeyPem().privateKey(), data);
        } catch (IOException e) {
            throw new EncryptionAndDecryptionException("密钥缺失, 无法验证信息");
        } catch (Exception exception) {
            throw new EncryptionAndDecryptionException("密码转换失败, 请重试");
        }
    }

    public String encrypt(String data) {
        try {
            return RsaUtils.encryptByPrivateKey(getKeyPem().privateKey(), data);
        } catch (IOException exception) {
            throw new EncryptionAndDecryptionException("密钥缺失, 无法加密");
        } catch (IllegalBlockSizeException exception) {
            throw new EncryptionAndDecryptionException("数据内容过长，加密失败");
        } catch (Exception exception) {
            throw new EncryptionAndDecryptionException("加密失败, 请重试");
        }
    }
}
